package de.haw.physics;

import de.haw.adt.implementation.Values;
import de.haw.adt.interfaces.ISpeed;
import de.haw.adt.interfaces.ITimeDiff;
import de.haw.vehicle.IVehicle;
import de.haw.vehicle.Porsche911GT2RS;
import de.haw.world.IWorld;

public class Acceleration {

	private IVehicle vehicle;
	private IWorld world;

	public Acceleration(IVehicle vehicle, IWorld world) {
		this.vehicle = vehicle;
		this.world = world;
	}

	public void accelerate(ITimeDiff deltaTime) {
		simulate(deltaTime);
	}

	public void brake(ITimeDiff deltaTime) {
		simulate(deltaTime);
	}

private void simulate(ITimeDiff deltaTime) {
		
		if (vehicle.getLevel() <= 0 && vehicle.getSpeed().getMs() < 1) 
			vehicle.setSpeed(Values.speedInMs(0.00000000001));
		
		//Antriebsleistung POWERPROP
		vehicle.setPowerProp(Math.abs(vehicle.getLevel()) * vehicle.getPowerPropMax());
		vehicle.setPowerBrake(vehicle.getMass().getKg() * world.getTraction() * Porsche911GT2RS.speedMax.getKmh());
		//Antriebskraft (aktuelle Traktion * Levelfaktor)
		vehicle.setForceProp(vehicle.getForcePropAbs() * Math.signum(vehicle.getLevel()));
		//Bremskraft (Bremshebelfaktor (startet bei 1 da min 1g | 0 ist aus) *  Erdanziehung * Masse des Autos * Faktor -1 (Vorzeichen setzen))
		vehicle.setForceBrakeAbs(vehicle.getPowerBrake()/vehicle.getSpeed().getMs());
		//Windwiderstandskraft (Drag Konstante vorgegeben kommt von EXTERN)
		vehicle.setForceDrag((vehicle.getDragConst() * Math.pow(vehicle.getSpeed().getMs(),2) * Math.signum(-vehicle.getSpeed().getMs())));
		//Gesamtkraft (Setzt sich zusammen aus: Antriebskraft + Windkraft (negativ) + Bremskraft (wenn vorhanden negativ))
		vehicle.setForce(Values.forceInN(vehicle.getForceProp() + vehicle.getForceDrag() + vehicle.getForceBrake()));
		//Fahrzeugbeschleunigung (Gesamtkraft / Masse) Gesamtkraft ist negativ wenn Bremse und Windwiderstand grÃ¶ÃŸer als Antrieb sind
		vehicle.setAcc(Values.accInMSs((vehicle.getForce().getN() / vehicle.getMass().getKg())));
		//Geschwindigkeit, Position und Zeit
		ISpeed val = Values.speedInMs(vehicle.getSpeed().getMs() + (vehicle.getAcc().getMSs() * deltaTime.getS()));
		vehicle.setSpeed(val);

		
		//ASR ANTI-SCHLUPF-REGELUNG: Reifen drehen durch wenn produzierte Traktion Ã¼ber der physikalisch mÃ¶glichen liegt. (ForcePropAbs)
		if (vehicle.isASR()){
			//ASR AN: Traktion geht nicht Ã¼ber ForcePropMax()
			vehicle.setForcePropAbs(Math.min(vehicle.getForcePropMax(), vehicle.getPowerProp() / (Math.abs(vehicle.getSpeed().getMs()))));
		}else{
			//ForcePropMax normal
			vehicle.setForcePropMax(vehicle.getMass().getKg() * world.getTraction());
			if (vehicle.getForcePropMax() < vehicle.getPowerProp() / (Math.abs(vehicle.getSpeed().getMs()))) {
				//ForcePropMax bei reduzierter Traktion
				vehicle.setForcePropMax((vehicle.getMass().getKg() * world.getTraction())/2);
			}else{
				vehicle.setForcePropMax(vehicle.getMass().getKg() * world.getTraction());
			}
			vehicle.setForcePropAbs(Math.min(vehicle.getForcePropMax(), vehicle.getPowerProp() / (Math.abs(vehicle.getSpeed().getMs()))));
		}
		
		//ABS ANTI-BLOCKIER-SYSTEM: Reifen verlieren Bodentraktion wenn Bremsverzögerung über 1g
		if (vehicle.isABS()) {
			//ABS AN: Auto bremst -> Verhindern des Bodenhaftungsverlustes durch Stotterbremsen. Kein kompletter Traktions verlust nur Reduktion 
			//der Traktion solange wie Bremsverzögerung über 1g
			vehicle.setForceBrakeMax(vehicle.getForcePropMax());
			if (Math.abs(vehicle.getForceBrake()) > vehicle.getForceBrakeMax()) {
				vehicle.setForceBrake((vehicle.getBrakelevel() * (vehicle.getForceBrakeAbs() / 2)) * Math.signum(-vehicle.getSpeed().getMs()));
			} else {
				vehicle.setForceBrake((vehicle.getBrakelevel() * vehicle.getForceBrakeAbs()) * Math.signum(-vehicle.getSpeed().getMs()));
			}
		} else {
			//ABS AUS: Auto bremst -> Auto verliert Bodenhaftung und rutscht vorwärts nur noch gebremst durch Wind
			vehicle.setForceBrake((vehicle.getBrakelevel() * vehicle.getForceBrakeAbs()) * Math.signum(-vehicle.getSpeed().getMs()));
		}
		
if (vehicle.getSpeed().getKmh() < 1) {
	vehicle.setDrive(false);
	vehicle.setForceBrake(0);
	vehicle.setSpeed(Values.speedInMs(0));
}
//Statusänderung
if (vehicle.getSpeed().getKmh() == 0 && vehicle.getLevel() != 0 && vehicle.isDrive() == false) {
	vehicle.setSpeed(Values.speedInMs(1));
	vehicle.setDrive(true);
}
}
}